package oauth2

import (
	"encoding/json"
	"github.com/go-oauth2/oauth2/v4"
	"github.com/go-oauth2/oauth2/v4/manage"
	"github.com/go-oauth2/oauth2/v4/models"
	"github.com/go-oauth2/oauth2/v4/server"
	"github.com/go-oauth2/oauth2/v4/store"
	"net/http"
)

// OAhth ...
type OAhth struct {
	Id     string `json:"id"`
	Secret string `json:"secret"`
	Domain string `json:"domain"`
}

type OauthStarter struct {
	manager *manage.Manager
	srv     *server.Server
	oauth   *OAhth
}

var oauthStarter *OauthStarter

// GetOauthInfo ...
func (o *OauthStarter)GetOauthInfo() *OAhth {
	return oauthStarter.oauth
}

// GetManager ...
func (o *OauthStarter)GetManager() *manage.Manager {
	return oauthStarter.manager
}

// GetSrv ...
func (o *OauthStarter)GetSrv() *server.Server {
	return oauthStarter.srv
}

// OauthParam ...
type OauthParam func(*OauthStarter)

// WithCustomToken 自定义token
func WithCustomToken(gen oauth2.AccessGenerate) OauthParam {
	return func(s *OauthStarter) {
		s.manager.MapAccessGenerate(gen)
	}
}

// WithValideUrl 验证url
func WithValideUrl(handler manage.ValidateURIHandler) OauthParam {
	return func(s *OauthStarter) {
		s.manager.SetValidateURIHandler(handler)
	}
}

// WithSetGrantType 设置模式
func WithSetGrantType(types ...oauth2.GrantType) OauthParam {
	return func(s *OauthStarter) {
		s.srv.SetAllowedGrantType(types...)
		for _, v := range types {
			switch v {
			case oauth2.AuthorizationCode:
				s.srv.SetAllowedResponseType(oauth2.Code)
			}
		}
	}
}

// WithPasswordAuthorizationHandler 设置模式
func WithPasswordAuthorizationHandler(handler server.PasswordAuthorizationHandler) OauthParam {
	return func(s *OauthStarter) {
		s.srv.SetPasswordAuthorizationHandler(handler)

	}
}

// WithAuthorizationHandler 重定向到 登陆页面
func WithAuthorizationHandler(handler server.UserAuthorizationHandler) OauthParam {
	return func(s *OauthStarter) {
		// 校验授权请求用户的handler, 会重定向到 登陆页面, 返回"", nil
		s.srv.SetUserAuthorizationHandler(handler)
	}
}

// NewOauth2 ...
func NewOauth2(config any,opt ...OauthParam) *OauthStarter {
	manager := manage.NewDefaultManager()
	oauthStarter = &OauthStarter{
		manager: manager,
		srv:     server.NewServer(server.NewConfig(), manager),
		oauth:   &OAhth{},
	}
	infoString, err := json.Marshal(config)
	if err != nil {
		panic(err)
	}
	err = json.Unmarshal(infoString, oauthStarter.oauth)
	if err != nil {
		panic(err)
	}
	// 设置 client 信息
	client_store := store.NewClientStore()
	client_store.Set(oauthStarter.oauth.Id, &models.Client{ID: oauthStarter.oauth.Id, Secret: oauthStarter.oauth.Secret, Domain: oauthStarter.oauth.Domain})

	manager.MustTokenStorage(store.NewMemoryTokenStore())
	// manger 包含 client 信息
	manager.MapClientStorage(client_store)
	// 从请求中获取clientID 和 clientSecret, 在获取 access token 校验过程中会被用到
	oauthStarter.srv.SetClientInfoHandler(func(r *http.Request) (clientID, clientSecret string, err error) {
		clientID = r.URL.Query().Get("client_id")
		clientSecret = r.URL.Query().Get("client_secret")
		return clientID, clientSecret, nil
	})
	// 允许使用 get 方法请求授权
	oauthStarter.srv.SetAllowGetAccessRequest(true)
	for _, param := range opt {
		param(oauthStarter)
	}
	return oauthStarter
}
